<!DOCTYPE html><html class="appearance-auto" lang="zh-CN"><head><meta charset="UTF-8"><title>【Spring源码解析系列】 Spring容器初始化</title><meta name="description" content="用创业者心态做好每一件事情！"><meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, initial-scale=1"><!-- Google Analytics --><!-- End Google Analytics -->
<!-- Baidu Analytics --><!-- End Baidu Analytics --><link rel="icon" href="/blog/images/favicon.png"><link rel="stylesheet" href="/blog/style/common/bulma.css"><link rel="stylesheet" href="/blog/style/base.css"><link rel="stylesheet" href="/blog/style/common/helper.css"><script src="/blog/js/common.js"></script><link rel="stylesheet" href="/blog/style/post.css"><link rel="stylesheet" href="/blog/style/themes/highlight-theme-light.css"><script src="/blog/js/highlight.pack.js"></script><meta name="description" content="
本文主要讲述Spring容器初始化，Spring Bean创建过程


体系图
配置文件中解析Bean概述AbstractApplicationContext.refresh()
-&amp;gt;AbstractApplicationContext.obtainFreshBeanFactory()
--&amp;gt;AbstractRefreshableApplicationContext.refreshBeanFactory()
---&amp;gt;AbstractXmlApplicationContext.loadBeanDefinitions()
----&amp;gt;AbstractBeanDefinitionReader.loadBeanDefinitions()
-----&amp;gt;XmlBeanDefinitionR.."><!-- hexo injector head_end start -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.12.0/dist/katex.min.css">

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hexo-math@4.0.0/dist/style.css">
<!-- hexo injector head_end end --><meta name="generator" content="Hexo 5.4.1"><link rel="alternate" href="/blog/atom.xml" title="janedler's blog" type="application/atom+xml">
</head><body class="is-flex is-flex-direction-column"><header class="header-widget is-flex-shrink-0 is-hidden-mobile"><div class="container is-fullhd is-flex is-justify-content-space-between is-align-items-center is-full-height"><section class="is-hidden-mobile is-flex-shrink-0"><h2><a href="/blog/">田园牧歌(*︶*)'s blog</a></h2></section><h3 class="is-hidden-mobile is-family-serif is-full-height is-flex is-align-items-center is-flex-shrink-0"><div class="is-full-height" id="postTopic"><p class="is-full-height is-flex-shrink-0 is-flex is-align-items-center is-justify-content-center">【Spring源码解析系列】 Spring容器初始化</p><p class="is-full-height is-flex-shrink-0 is-flex is-align-items-center is-justify-content-center">点击返回顶部</p></div></h3><aside class="is-flex-shrink-0"><h3 class="is-inline-block"><a href="/blog/">首页</a></h3><h3 class="is-inline-block"><a href="/blog/about">关于</a></h3><h3 class="is-inline-block"><a href="/blog/archives">归档</a></h3></aside></div></header><header class="is-flex header-widget is-flex-shrink-0 is-align-items-center is-justify-content-center is-hidden-tablet"><h3 class="is-inline-block"><a href="/blog/">首页</a></h3><h3 class="is-inline-block"><a href="/blog/about">关于</a></h3><h3 class="is-inline-block"><a href="/blog/archives">归档</a></h3></header><main><main class="container is-max-widescreen content section post-page pt-4 px-4"><div class="columns is-flex-desktop is-justify-content-center is-flex-direction-row-reverse"><div class="column is-3 is-hidden-mobile"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%93%E7%B3%BB%E5%9B%BE"><span class="toc-text">体系图</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E8%A7%A3%E6%9E%90Bean%E6%A6%82%E8%BF%B0"><span class="toc-text">配置文件中解析Bean概述</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%85%A8%E8%BF%87%E7%A8%8B%E5%BF%AB%E7%85%A7"><span class="toc-text">全过程快照</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#IOC%E5%AE%B9%E5%99%A8%E5%88%9D%E5%A7%8B%E5%8C%96%E5%9F%BA%E6%9C%AC%E6%AD%A5%E9%AA%A4"><span class="toc-text">IOC容器初始化基本步骤</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Refresh"><span class="toc-text">Refresh</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%88%9D%E5%A7%8B%E5%8C%96%E4%B8%8A%E4%B8%8B%E6%96%87%E7%8E%AF%E5%A2%83-prefareRefresh"><span class="toc-text">初始化上下文环境-prefareRefresh</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Bean%E5%8A%A0%E8%BD%BD-obtainFreshBeanFactory"><span class="toc-text">Bean加载-obtainFreshBeanFactory</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#IOC%E5%AE%B9%E5%99%A8%E5%90%8E%E7%BB%AD%E6%93%8D%E4%BD%9C%E5%9C%A8%E5%85%B6%E4%BB%96%E6%96%87%E6%A1%A3%E4%B8%AD%E4%BB%8B%E7%BB%8D"><span class="toc-text">IOC容器后续操作在其他文档中介绍</span></a></li></ol></li></ol></div><div class="column is-9"><header class="my-4"><a href="/blog/tags/Java"><i class="tag post-item-tag">Java</i></a><a href="/blog/tags/Spring"><i class="tag post-item-tag">Spring</i></a></header><h1 class="mt-0 mb-1 is-family-serif" id="postTitle">【Spring源码解析系列】 Spring容器初始化</h1><time class="has-text-grey" datetime="2022-11-28T16:00:00.000Z">2022-11-29</time><article class="mt-2 post-content"><p><img src="https://janedler.oss-cn-beijing.aliyuncs.com/images/spring.png"></p>
<p>本文主要讲述Spring容器初始化，Spring Bean创建过程</p>
<span id="more"></span>

<h2 id="体系图"><a href="#体系图" class="headerlink" title="体系图"></a>体系图</h2><p><img src="https://janedler.oss-cn-beijing.aliyuncs.com/images/202211281340076.png" alt="AbstractRefreshableApplicationContext"></p>
<h2 id="配置文件中解析Bean概述"><a href="#配置文件中解析Bean概述" class="headerlink" title="配置文件中解析Bean概述"></a>配置文件中解析Bean概述</h2><pre><code class="bash">AbstractApplicationContext.refresh()
-&gt;AbstractApplicationContext.obtainFreshBeanFactory()
--&gt;AbstractRefreshableApplicationContext.refreshBeanFactory()
---&gt;AbstractXmlApplicationContext.loadBeanDefinitions()
----&gt;AbstractBeanDefinitionReader.loadBeanDefinitions()
-----&gt;XmlBeanDefinitionReader.loadBeanDefinitions()
------&gt;XmlBeanDefinitionReader.doLoadBeanDefinitions()
-------&gt;XmlBeanDefinitionReader.registerBeanDefinitions()
--------&gt;DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions()
---------&gt;DefaultBeanDefinitionDocumentReader.parseBeanDefinitions()
----------&gt;DefaultBeanDefinitionDocumentReader.parseDefaultElement()
-----------&gt;DefaultBeanDefinitionDocumentReader.processBeanDefinition()
------------&gt;BeanDefinitionReaderUtils.registerBeanDefinition()
-------------&gt;DefaultListableBeanFactory.registerBeanDefinition()
</code></pre>
<h2 id="全过程快照"><a href="#全过程快照" class="headerlink" title="全过程快照"></a>全过程快照</h2><pre><code class="java">//定位-&gt;载入-&gt;注册
//根据xml配置文件创建Resource资源对象，该对象中包含了BeanDefinition的信息
ClassPathResource resource = new ClassPathResource(&quot;application-context.xml&quot;);
//创建DefaultListableBeanFactory
DefaultListableBeanFacotory factory = new DefaultListableBeanFactory();
//创建XmlBeanDefinitionReader读取器，用于载入BeanDefinition，之所以BeanFactory作为参数，是因为会将读取的信息回调配置给factory
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
//XmlBeanDefinitionReader执行载入BeanDefinition的方法，最后会完成Bean的载入和注册。完成后Bean就成功的放置到IOC容器当中，以后我们就可以从中获得到Bean来使用
reader.loadBeanDefinitions(resource);
</code></pre>
<p>1、定位：BeanDefinition的Resource定位，得到一个Resource<br>2、载入：加载Spring配置文件<br>3、注册：Bean的解析主要对Spring配置文件的解析，解析成一个BeanDefinition，对bean的说明而已，bean还没有正在的产生</p>
<h2 id="IOC容器初始化基本步骤"><a href="#IOC容器初始化基本步骤" class="headerlink" title="IOC容器初始化基本步骤"></a>IOC容器初始化基本步骤</h2><pre><code class="bash">1、初始化的入口在容器实现中refresh()调用来完成
2、对bean定义载入IOC容器使用的方法是loadBeanDefinition
</code></pre>
<p>详细描述：<br>通过ResourceLoader来完成资源文件位置的定位，DefaultResourceLoader是默认的实现，同时上下文本身就给出了ResourceLoader的实现，可以从类路径，文件系统，URL等方式来定为资源位置。如果是XmlBeanFactory作为容器，那么需要为它指定bean定义的资源，也就是说bean定义文件时通过抽象成Resource来被IOC容器处理，容器通过BeanDefinitionReader来完成定义信息的解析和Bean信息的注册，往往使用的是XmlBeanDefinitionReader来解析bean的xml定义文件，实际的处理过程是委托给BeanDefinitionParserDelegate来完成的，从而得到bean的定义信息，这些信息在Spring中使用BeanDefinition对象来表示，这个名字可以让我们想到loadBeanDefinition，RegisterBeanDefinition这些相关方法，他们都是为处理BeanDefinition服务的，容器解析得到BeanDefinitionIOC以后，需要把它在IOC容器中注册，这由IOC实现BeanDefinitionRegistry接口来实现，注册过程就是在IOC容器内部维护一个ConcurrentHashMap来保存得到的BeanDefinition的过程。这个HashMap是IOC容器持有bean信息的场所，以后bean的操作都是围绕这个HashMap来实现。</p>
<h2 id="Refresh"><a href="#Refresh" class="headerlink" title="Refresh"></a>Refresh</h2><p>位置：AbstractApplicationContext::refresh</p>
<pre><code class="java">//容器初始化的过程，读入Bean定义资源，并解析注册
//在创建IOC容器前，如果已经有容器存在，则需要把已有的容器销毁和关闭，以保证在refresh之后使用
//的是新建立起来的IOC容器,refresh的作用类似于对IOC容器的重启，在新建立好容器中对容器进行初始化，
//对Bean定义资源进行载入 IOC容器一定是单例的
@Override
public void refresh() throws BeansException, IllegalStateException &#123;
    synchronized (this.startupShutdownMonitor) &#123;
        StartupStep contextRefresh = this.applicationStartup.start(&quot;spring.context.refresh&quot;);
        //调用容器准备刷新的方法，获取容器的当前时间，同时给容器设置同步标识
        // Prepare this context for refreshing.
        prepareRefresh();
        //告诉子类启动refreshBeanFactory()方法，Bean定义资源文件的载入从子类refreshBeanFactory()方法启动
        // Tell the subclass to refresh the internal bean factory.
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        //为BeanFactory配置容器特性，例如类加载器，时间处理器等
        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);
        try &#123;
            //为容器的某些子类指定特殊的BeanPost事件处理器
            //此方法允许子类在所有的bean尚未初始化之前注册BeanPostProcessor。空实现且没有子类覆盖。
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);
            StartupStep beanPostProcess = this.applicationStartup.start(&quot;spring.context.beans.post-process&quot;);
            // Invoke factory processors registered as beans in the context.
            //调用所有注册的BeanFactoryPostProcessor的Bean
            invokeBeanFactoryPostProcessors(beanFactory);
            //为BeanFactory注册BeanPost事件处理器
            //BeanPostProcessor是Bean后置处理器，用于监听容器触发的事件
            // Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);
            beanPostProcess.end();
            //初始化信息源，和国际化相关
            // Initialize message source for this context.
            initMessageSource();
            //初始化容器事件传播
            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();
            //调用子类某些特殊Bean初始化方法
            // Initialize other special beans in specific context subclasses.
            onRefresh();
            //为事件传播器注册事件监听器
            // Check for listener beans and register them.
            registerListeners();
            //初始化所有剩余的单例Bean
            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);
            //初始化容器的生命周期事件处理器，并发布容器的生命周期事件
            // Last step: publish corresponding event.
            finishRefresh();
        &#125;
        catch (BeansException ex) &#123;
            if (logger.isWarnEnabled()) &#123;
                logger.warn(&quot;Exception encountered during context initialization - &quot; +
                            &quot;cancelling refresh attempt: &quot; + ex);
            &#125;
            //销毁以创建的单例Bean
            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();
            //取消refresh操作，重置容器的同步标识
            // Reset &#39;active&#39; flag.
            cancelRefresh(ex);
            // Propagate exception to caller.
            throw ex;
        &#125;
        finally &#123;
            // Reset common introspection caches in Spring&#39;s core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
            contextRefresh.end();
        &#125;
    &#125;
&#125;
</code></pre>
<h3 id="初始化上下文环境-prefareRefresh"><a href="#初始化上下文环境-prefareRefresh" class="headerlink" title="初始化上下文环境-prefareRefresh"></a>初始化上下文环境-prefareRefresh</h3><p>位置：AbstractApplicationContext::prefareRefresh<br>初始化上下文环境，对系统的环境变量或者系统属性进行准备和校验,如环境变量中必须设置某个值才能运行，否则不能运行<br>1、设置context启动时间<br>2、设置context的当前状态<br>3、初始化context environment中占位符<br>4、对属性进行必要的验证</p>
<pre><code class="java">protected void prepareRefresh() &#123;
        // 设置启动日期
        this.startupDate = System.currentTimeMillis();
        //设置context当前状态
        this.closed.set(false);
        this.active.set(true);
        ...省略...
        // Initialize any placeholder property sources in the context environment.
        //初始化context environment（上下文环境）中的占位符属性来源
        initPropertySources();
        // Validate that all properties marked as required are resolvable:
        // see ConfigurablePropertyResolver#setRequiredProperties
        //对属性进行必要的验证
        getEnvironment().validateRequiredProperties();
        // Store pre-refresh ApplicationListeners...
        if (this.earlyApplicationListeners == null) &#123;
            this.earlyApplicationListeners = new LinkedHashSet&lt;&gt;(this.applicationListeners);
        &#125;
        else &#123;
            // Reset local application listeners to pre-refresh state.
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        &#125;
        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet&lt;&gt;();
    &#125;
</code></pre>
<h3 id="Bean加载-obtainFreshBeanFactory"><a href="#Bean加载-obtainFreshBeanFactory" class="headerlink" title="Bean加载-obtainFreshBeanFactory"></a>Bean加载-obtainFreshBeanFactory</h3><p>位置：AbstractApplicationContext::refresh<br>创建并初始化BeanFactory，告诉子类启动refreshBeanFactory()方法，Bean定义资源文件的载入从子类refreshBeanFactory()方法启动;<br>描述：在执行完obtainFreshBeanFactory()方法后，得到了BeanFactory对象，并使用BeanDefinition来描述bean，通过BeanFactory里面的Map&lt;String, BeanDefinition&gt; beanDefinitionMap = new ConcurrentHashMap&lt;&gt;(256)进行存储。此时Bean只是加载进来，并没有进行实例化。</p>
<pre><code class="java">protected ConfigurableListableBeanFactory obtainFreshBeanFactory() &#123;
    //这里使用了委派设计模式，父类定义了抽象的refreshBeanFactory()方法，具体实现调用了子类容器的refreshBeanFactory()
    //刷新BeanFactory
    refreshBeanFactory();
    //获取BeanFactory
    return getBeanFactory();
&#125;
</code></pre>
<p>AbstractRefreshableApplicationContext::refreshBeanFactory<br>1、判断当前容器是否存在一个BeanFactory，如果存在则对其进行销毁和关闭<br>2、调用createBeanFactory()创建一个 BeanFactory 实例，其实就是 DefaultListableBeanFactory<br>3、自定义BeanFactory<br>4、加载BeanDefinition<br>5、将创建好的 bean 工厂的引用交给的 context 来管理</p>
<pre><code class="java">@Override
protected final void refreshBeanFactory() throws BeansException &#123;
    //如果已经有了容器，销毁容器中的bean，关闭容器
    if (hasBeanFactory()) &#123;
        destroyBeans();
        closeBeanFactory();
    &#125;
    try &#123;
        //创建IOC容器
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        beanFactory.setSerializationId(getId());
        //对IOC容器进行定制化，如设置启动参数，开启注解的自动装配等
        customizeBeanFactory(beanFactory);
        //调用载入Bean定义的方法，主要这里又使用了一个委派模式，在当前类中定义了抽象的loadBeanDefinitions，具体由子类去实现
        loadBeanDefinitions(beanFactory);
        this.beanFactory = beanFactory;
    &#125;
    catch (IOException ex) &#123;
        throw new ApplicationContextException(&quot;I/O error parsing bean definition source for &quot; + getDisplayName(), ex);
    &#125;
&#125;
</code></pre>
<p>加载bean（loadBeanDefinitions）定义在AbstractRefreshableApplicationContext中<br><img src="https://janedler.oss-cn-beijing.aliyuncs.com/images/202211281430170.png" alt="img"></p>
<pre><code class="java">protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)throws BeansException, IOException;
</code></pre>
<p>1、AbstractXmlApplicationContext（ClassPathXmlApplicationContext，FileSystemXmlApplicationContext）<br>2、AnnotationConfigWebApplicationContext<br>3、GroovyWebApplicationContext<br>4、XmlWebApplicationContext<br>以AbstractXmlApplicationContext::loadBeanDefinitions为例子</p>
<pre><code class="java">//主要是对spring注入配置文件的解析，主要使用到BeanDefinitionReader和BeanDefinitionDocumentReader两个接口相关的实现类
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException &#123;
    // Create a new XmlBeanDefinitionReader for the given BeanFactory.
    //创建XmlBeanDefinitionReader，即创建Bean读取器，并通过回调设置到容器中去，容器使用该读取Bean定义的资源
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    // Configure the bean definition reader with this context&#39;s
    // resource loading environment.
    //为Bean读取器设置Spring资源加载器，AbstractXmlApplicationContext的
    //祖先父类AbstractApplicationContext继承DefaultResourceLoader，因此，容器本身也是一个资源加载器
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    //为Bean读取器设置SAX xml解析器DOM4J
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    // Allow a subclass to provide custom initialization of the reader,
    // then proceed with actually loading the bean definitions.
    //当Bean读取器读取Bean定义的Xml资源文件时，启用Xml的校验机制
    initBeanDefinitionReader(beanDefinitionReader);
    //Bean读取器真正实现加载的方法
    loadBeanDefinitions(beanDefinitionReader);
&#125;
</code></pre>
<pre><code class="java">//Xml Bean读取器加载Bean定义资源
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException &#123;
    //读取Bean定义资源的定位
    //这里使用了一个委派模式，调用子类的获取Bean定义资源定位的方法
    //该方法在ClassPathXmlApplicationContext中实现，对于我们
    //举例分析源码的FileSystemXmlApplicationContext没有使用该方法
    Resource[] configResources = getConfigResources();
    if (configResources != null) &#123;
        //Xml Bean读取器调用其父类的AbstracBeanDefinitionReader读取定位的Bean定义资源
        reader.loadBeanDefinitions(configResources);
    &#125;
    //如果子类中读取的Bean定义资源定位为空，则获取FileSystemXmlApplicationContext构造方法中
    //SetConfigLocations方法设置的资源
    String[] configLocations = getConfigLocations();
    if (configLocations != null) &#123;
        //Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位
        reader.loadBeanDefinitions(configLocations);
    &#125;
&#125;
</code></pre>
<p>reader.loadBeanDefinitions(configResources)最后调用的是XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource)</p>
<pre><code class="java">//这里是载入XML形式Bean定义资源文件方法
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException &#123;
    Assert.notNull(encodedResource, &quot;EncodedResource must not be null&quot;);
    if (logger.isTraceEnabled()) &#123;
        logger.trace(&quot;Loading XML bean definitions from &quot; + encodedResource);
    &#125;

    Set&lt;EncodedResource&gt; currentResources = this.resourcesCurrentlyBeingLoaded.get();
    if (!currentResources.add(encodedResource)) &#123;
        throw new BeanDefinitionStoreException(
                    &quot;Detected cyclic loading of &quot; + encodedResource + &quot; - check your import definitions!&quot;);
    &#125;
    //将资源文件转换为InputStream的IO流
    try (InputStream inputStream = encodedResource.getResource().getInputStream()) &#123;
        //从InputStream中得到XML的解析源
        InputSource inputSource = new InputSource(inputStream);
        if (encodedResource.getEncoding() != null) &#123;
            inputSource.setEncoding(encodedResource.getEncoding());
        &#125;
        //这里是具体的读取过程 在Spring里面doXXXX都是具体干活的方法
        return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
    &#125;
    catch (IOException ex) &#123;
        throw new BeanDefinitionStoreException(
                    &quot;IOException parsing XML document from &quot; + encodedResource.getResource(), ex);
    &#125;
    finally &#123;
        currentResources.remove(encodedResource);
        if (currentResources.isEmpty()) &#123;
            this.resourcesCurrentlyBeingLoaded.remove();
        &#125;
    &#125;
&#125;
</code></pre>
<p>doLoadBeanDefinitions(inputSource, encodedResource.getResource())开始真正解析Bean过程</p>
<pre><code class="java">//从特定XML文件中实际载入Bean定义资源的方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException &#123;
    try &#123;
        //将XML文件转换为DOM对象，解析过程由documentLoader实现
        Document doc = doLoadDocument(inputSource, resource);
        //这里是启动对Bean定义解析的详细过程，该解析过程会用到Spring的Bean配置规则
        int count = registerBeanDefinitions(doc, resource);
        if (logger.isDebugEnabled()) &#123;
            logger.debug(&quot;Loaded &quot; + count + &quot; bean definitions from &quot; + resource);
        &#125;
        return count;
    &#125;
    ...省略catch...
&#125;
</code></pre>
<p>1、通过doLoadDocument将XML解析成Document对象;<br>2、创建BeanDefinitionDocumentReader对象，并调用该对象的registerBeanDefinitions方法从Document对象中解析并注册bean;</p>
<pre><code class="java">//按照Spring的Bean语义要求将Bean定义资源解析并转换为容器内部的数据结构
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException &#123;
    //得到BeanDefinitionDocumentReader来对XML格式的BeanDefinition解析
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    //获得容器中注册的Bean的数量
    int countBefore = getRegistry().getBeanDefinitionCount();
    //解析过程入口，这里使用了委派模式，BeanDefinitionDocumentReader只是个接口，
    //具体的解析实现过程有实现类DefaultDefinitionDocumentReader完成
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    //统计解析的Bean的数量
    return getRegistry().getBeanDefinitionCount() - countBefore;
&#125;
</code></pre>
<pre><code class="java">//根据SpringDTD对Bean的定义规则解析Bean定义的Document对象
protected void doRegisterBeanDefinitions(Element root) &#123;
    BeanDefinitionParserDelegate parent = this.delegate;
    //获得Document的根元素
    //BeanDefinitionParserDelegate中定义了Spring Bean定义XML文件的各种元素
    this.delegate = createDelegate(getReaderContext(), root, parent);
    if (this.delegate.isDefaultNamespace(root)) &#123;
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) &#123;
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) &#123;
                if (logger.isDebugEnabled()) &#123;
                    logger.debug(&quot;Skipped XML bean definition file due to specified profiles [&quot; + profileSpec +
                                &quot;] not matching: &quot; + getReaderContext().getResource());
                &#125;
                return;
            &#125;
        &#125;
    &#125;
    //在解析Bean之前，进行自定义的解析，增强解析过程的可扩展性
    preProcessXml(root);
    //从Document的根元素开始进行Bean定义的Document对象
    parseBeanDefinitions(root, this.delegate);
    //从Document的根元素开始进行Bean定义的Document对象
    postProcessXml(root);
    this.delegate = parent;
&#125;
</code></pre>
<pre><code class="java">//使用Spring的Bean规则从Document的根元素开始进行Bean定义的Document对象
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) &#123;
    //Bean定义的Document对象使用了Spring默认的XML命名空间
    if (delegate.isDefaultNamespace(root)) &#123;
        //获取Bean定义的Document对象根元素的所有子节点
        NodeList nl = root.getChildNodes();
        for (int i = 0; i &lt; nl.getLength(); i++) &#123;
            Node node = nl.item(i);
            //获得Document节点是XML元素节点
            if (node instanceof Element ele) &#123;
                //Bean定义的Document的元素节点使用的是Spring默认的XML命名空间
                if (delegate.isDefaultNamespace(ele)) &#123;
                    //使用Spring的Bean规则解析元素节点
                    parseDefaultElement(ele, delegate);
                &#125;
                else &#123;
                    //没有使用Spring默认的XML命名空间，则使用用户自定义的解析规则解析元素节点
                    delegate.parseCustomElement(ele);
                &#125;
            &#125;
        &#125;
    &#125;
    else &#123;
        delegate.parseCustomElement(root);
    &#125;
&#125;
</code></pre>
<pre><code class="java">//使用Spring的Bean规则解析Document元素节点
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) &#123;
    //如果元素节点是&lt;Import&gt;导入元素，进行导入解析
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) &#123;
        importBeanDefinitionResource(ele);
    &#125;
    //如果元素节点是&lt;Alias&gt;别名元素，进行别名解析
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) &#123;
        processAliasRegistration(ele);
    &#125;
    //元素节点既不是导入元素，也不是别名元素，即普通的&lt;Bean&gt;元素
    //按照Spring的Bean规则解析元素
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) &#123;
        processBeanDefinition(ele, delegate);
    &#125;
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) &#123;
        // recurse
        doRegisterBeanDefinitions(ele);
    &#125;
&#125;
</code></pre>
<pre><code class="java">//解析Bean定义资源Document对象的普通元素
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) &#123;
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    //BeanDefinitionHolder是对BeanDefinition的封装，即Bean定义的封装类
    //对Document对象中&lt;Bean&gt;元素的解析由BeanDefinitionParserDelegate实现
    //BeanDefinitionHolder dbHolder =delegate.parseBeanDefinitionElement(ele)
    if (bdHolder != null) &#123;
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try &#123;
            //向SpringIOC容器注册解析得到的Bean定义，这是Bean定义向IOC容器注册的入口
            // Register the final decorated instance.
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        &#125;
        catch (BeanDefinitionStoreException ex) &#123;
                getReaderContext().error(&quot;Failed to register bean definition with name &#39;&quot; +
                        bdHolder.getBeanName() + &quot;&#39;&quot;, ele, ex);
        &#125;
        //在完成向SpringIOC容器注册解析得到的Bean定义之后，发送注册事件
        // Send registration event.
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    &#125;
&#125;
</code></pre>
<pre><code class="java">//将解析的BeanDefinition注册到容器中
public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException &#123;
    // Register bean definition under primary name.
    //获取解析的DeanDefinition的名次
    String beanName = definitionHolder.getBeanName();
    //向IOC容器注册BeanDefinition
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    // Register aliases for bean name, if any.
    //如果解析的BeanDefinition有别名，向容器为其注册别名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) &#123;
        for (String alias : aliases) &#123;
            registry.registerAlias(beanName, alias);
        &#125;
    &#125;
&#125;
</code></pre>
<p>DefaultListableBeanFactory::registerBeanDefinition</p>
<pre><code class="java">//向IOC容器注册解析BeanDefinition
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException &#123;

        Assert.hasText(beanName, &quot;Bean name must not be empty&quot;);
        Assert.notNull(beanDefinition, &quot;BeanDefinition must not be null&quot;);
        //校验解析的BeanDefinition
        if (beanDefinition instanceof AbstractBeanDefinition abd) &#123;
            try &#123;
                abd.validate();
            &#125;
            catch (BeanDefinitionValidationException ex) &#123;
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        &quot;Validation of bean definition failed&quot;, ex);
            &#125;
        &#125;
        //注册过程
        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        //检查是否有同名的BeanDefinition已经在容器IOC中注册，如果已经注册，
        //并且不允许覆盖已经注册的Bean，则抛出注册失败异常
        if (existingDefinition != null) &#123;
            if (!isAllowBeanDefinitionOverriding()) &#123;
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            &#125;
            else if (existingDefinition.getRole() &lt; beanDefinition.getRole()) &#123;
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                //如果允许覆盖，则同名的Bean，后注册的覆盖先注册的
                if (logger.isInfoEnabled()) &#123;
                    logger.info(&quot;Overriding user-defined bean definition for bean &#39;&quot; + beanName +
                            &quot;&#39; with a framework-generated bean definition: replacing [&quot; +
                            existingDefinition + &quot;] with [&quot; + beanDefinition + &quot;]&quot;);
                &#125;
            &#125;
            else if (!beanDefinition.equals(existingDefinition)) &#123;
                if (logger.isDebugEnabled()) &#123;
                    logger.debug(&quot;Overriding bean definition for bean &#39;&quot; + beanName +
                            &quot;&#39; with a different definition: replacing [&quot; + existingDefinition +
                            &quot;] with [&quot; + beanDefinition + &quot;]&quot;);
                &#125;
            &#125;
            else &#123;
                if (logger.isTraceEnabled()) &#123;
                    logger.trace(&quot;Overriding bean definition for bean &#39;&quot; + beanName +
                            &quot;&#39; with an equivalent definition: replacing [&quot; + existingDefinition +
                            &quot;] with [&quot; + beanDefinition + &quot;]&quot;);
                &#125;
            &#125;
            this.beanDefinitionMap.put(beanName, beanDefinition);
        &#125;
        else &#123;
            if (isAlias(beanName)) &#123;
                if (!isAllowBeanDefinitionOverriding()) &#123;
                    String aliasedName = canonicalName(beanName);
                    if (containsBeanDefinition(aliasedName)) &#123;  // alias for existing bean definition
                        throw new BeanDefinitionOverrideException(
                                beanName, beanDefinition, getBeanDefinition(aliasedName));
                    &#125;
                    else &#123;  // alias pointing to non-existing bean definition
                        throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                                &quot;Cannot register bean definition for bean &#39;&quot; + beanName +
                                &quot;&#39; since there is already an alias for bean &#39;&quot; + aliasedName + &quot;&#39; bound.&quot;);
                    &#125;
                &#125;
                else &#123;
                    removeAlias(beanName);
                &#125;
            &#125;
            //IOC容器中没有已经注册同名的Bean，按正常注册流程注册
            if (hasBeanCreationStarted()) &#123;
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                synchronized (this.beanDefinitionMap) &#123;
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List&lt;String&gt; updatedDefinitions = new ArrayList&lt;&gt;(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    removeManualSingletonName(beanName);
                &#125;
            &#125;
            else &#123;
                // Still in startup registration phase
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                removeManualSingletonName(beanName);
            &#125;
            this.frozenBeanDefinitionNames = null;
        &#125;

        if (existingDefinition != null || containsSingleton(beanName)) &#123;
            //重置所有已经注册过的BeanDefinition缓存
            resetBeanDefinition(beanName);
        &#125;
        else if (isConfigurationFrozen()) &#123;
            clearByTypeCache();
        &#125;
    &#125;
</code></pre>
<h3 id="IOC容器后续操作在其他文档中介绍"><a href="#IOC容器后续操作在其他文档中介绍" class="headerlink" title="IOC容器后续操作在其他文档中介绍"></a>IOC容器后续操作在其他文档中介绍</h3></article><section class="jump-container is-flex is-justify-content-space-between my-6"><!-- em is empty placeholder--><a class="button is-default" href="/blog/2022/11/29/Spring/Spring%E8%A7%A3%E5%86%B3%E5%BE%AA%E7%8E%AF%E4%BE%9D%E8%B5%96/" title="【Spring源码解析系列】 Spring解决循环依赖"><i class="iconfont icon-prev mr-2 has-text-grey"></i><span class="has-text-weight-semibold">上一页: 【Spring源码解析系列】 Spring解决循环依赖</span></a><a class="button is-default" href="/blog/2022/11/29/Spring/Spring%E6%89%A9%E5%B1%95%E5%8A%9F%E8%83%BD-BeanDefinitionRegistryPostProcessor/" title="【Spring源码解析系列】 BeanDefinitionRegistryPostProcessor"><span class="has-text-weight-semibold">下一页: 【Spring源码解析系列】 BeanDefinitionRegistryPostProcessor</span><i class="iconfont icon-next ml-2 has-text-grey"></i></a></section><article class="mt-6 comment-container"><script async repo="janedler/blog" src="https://utteranc.es/client.js" issue-term="pathname" theme="preferred-color-scheme"></script></article></div></div></main></main><footer class="is-flex is-flex-direction-column is-align-items-center is-flex-shrink-0 is-family-serif"><section class="sns-container"><!-- Github--><a title="github" target="_blank" rel="noopener nofollow" href="//github.com//janedler"><i class="iconfont icon-github"></i></a><!-- Ins--><!-- RSS--><a title="rss" target="_blank" rel="noopener nofollow" href="/blog/atom.xml"><i class="iconfont icon-rss"></i></a><!-- 知乎--><!-- 领英--><!-- 脸书--></section><p><span>Copyright ©</span><span> 田园牧歌(*︶*) 2022</span></p><div class="is-flex is-justify-content-center is-flex-wrap-wrap"><p>Powered by Hexo &verbar;&nbsp;</p><p class="is-flex is-justify-content-center"><a title="Hexo theme author" target="_blank" rel="noopener" href="//github.com/haojen">Theme by Haojen&nbsp;</a></p><div style="margin-top: 2px"><a class="github-button" title="github-button" target="_blank" rel="noopener" href="https://github.com/haojen/hexo-theme-Claudia" data-color-scheme="no-preference: light; light: light; dark: dark;" data-show-count="true"></a></div></div><div><span></span></div></footer><script async defer src="https://buttons.github.io/buttons.js"></script><script src="/blog/js/post.js"></script></body></html>